package com.hilda.HTMLParserTesting.utils;

import java.io.IOException;
import java.net.URL;
import java.util.Iterator;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;

public class UrlUnshortUtils extends DefaultHttpClient {
	public static final int NO_CONNECTION = -1;
	public static final int UNSHORT_OK = 100;
	public static final int UNSHORT_TRY_AGAIN = 200;
	public static final int UNSHORT_LONG_URL = 300;
	public static final int UNSHORT_KO = -100;

	public static final int UNTINY_API_OK = 100;
	/**
	 * UNTINY CODES http://untiny.com/api/#service=0
	 */
	public static final int UNTINY_API_ERROR_INVALID_URL = 0;
	public static final int UNTINY_API_ERROR_UNSUPPORTED = 1;
	public static final int UNTINY_API_ERROR_CONN_FAILED = 2;
	public static final int UNTINY_API_ERROR_UNABLE_GET = 3;

	private static final String UNTINY_API_EXTRACT = "http://untiny.me/api/1.0/extract/?url=";
	private static final String UNTINY_API_SERVICES = "http://untiny.me/api/1.0/services/?format=json";

	public static final int GET_SERVICES = 1;

	private JSONObject mUntinyServices;
	private boolean firstUnshort = true;

	private UrlUnshortCallBack mUrlUnshortCallBack;

	public UrlUnshortUtils(UrlUnshortCallBack urlUnshortCallBack) {
		getServicesUntiny();
		mUrlUnshortCallBack = urlUnshortCallBack;
	}

	/**
	 * Uses http://untiny.com/ API to get the unshort url
	 * 
	 * @param String
	 *            shortUrl
	 * @return URL
	 */

	public void unshortUrl(String shortUrl) {
		Log.i("crawDroid", ".unshortUrl(), find long url for = " + shortUrl);
		URL unshortedUrl = null;

		try {
			unshortedUrl = new URL(shortUrl);

		} catch (IOException e) {
			Log.e("crawDroid", ".unshortUrl(): " + e.getMessage());
		}

		if (unshortedUrl != null) {
			if (shortServiceAreAvailable(unshortedUrl.getHost())) {

				UnshortUrlAsyncTask unshortUrlAsyncTask = new UnshortUrlAsyncTask();
				unshortUrlAsyncTask.execute(UNTINY_API_EXTRACT + shortUrl
						+ "&format=json");
			}else if(firstUnshort){
				firstUnshort=false;
				mUrlUnshortCallBack.onExtractUrl(UNSHORT_LONG_URL, unshortedUrl);
			}

		}
		// Log.i("crawDroid",
		// ".unshortUrl(), long url found = "
		// + unshortedUrl.toExternalForm());
		// return null;
	}

	private class UnshortUrlAsyncTask extends AsyncTask<String, Void, String> {

		@Override
		protected String doInBackground(String... params) {
			int responseCode = HttpStatus.SC_NOT_FOUND;
			HttpResponse httpResponse = null;
			HttpEntity entity = null;
			String content = null;

			try {

				HttpGet mHttpGet = new HttpGet(params[0]);
				DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
				httpResponse = defaultHttpClient.execute(mHttpGet);

				responseCode = httpResponse.getStatusLine().getStatusCode();

				if (responseCode == HttpStatus.SC_OK) {
					entity = httpResponse.getEntity();
					content = EntityUtils.toString(entity);
				} else {
					Log.e("crawDroid", ".HttpGetAsyncTask() response code: "
							+ responseCode);
				}
			} catch (ClientProtocolException e) {
				Log.e("crawDroid", ".unshortUrlAsyncTask(): " + e.getMessage());
			} catch (IOException e) {
				Log.e("crawDroid", ".unshortUrlAsyncTask(): " + e.getMessage());
			} catch (ParseException e) {
				Log.e("crawDroid", ".unshortUrlAsyncTask(): " + e.getMessage());
			}

			return content;
		}

		@Override
		protected void onPostExecute(String content) {
			URL unshortedUrl = null;
			URL nextUnshortedUrl = null;
			int result = UNSHORT_KO;

			try {
				JSONObject jsonObject = new JSONObject(content);
				if (!jsonObject.isNull("org_url")) {
					unshortedUrl = new URL(jsonObject.getString("org_url"));

					if (unshortedUrl != null) {

						Log.v("crawDroid", ".unshortUrl(), resolved url = "
								+ unshortedUrl.toExternalForm()
								+ " Try for more short URL");

						result = UNSHORT_OK;

						if (shortServiceAreAvailable(unshortedUrl.getHost())) {
							result = UNSHORT_TRY_AGAIN;
							unshortUrl(unshortedUrl.toExternalForm());
						}
					}



				} else if (!jsonObject.isNull("error")) {
					JSONArray jsonArray = jsonObject.getJSONArray("error");
					result = jsonArray.getInt(0);
					Log.e("crawDroid", ".unshortUrl(), UNTINY API ERROR "
							+ result + " " + jsonArray.getString(1));
				}

			} catch (JSONException e) {
				Log.e("crawDroid", ".unshortUrlAsyncTask().onPostExecute(): "
						+ e.getMessage());
			} catch (ParseException e) {
				Log.e("crawDroid", ".unshortUrlAsyncTask().onPostExecute(): "
						+ e.getMessage());
			} catch (IOException e) {
				Log.e("crawDroid", ".unshortUrlAsyncTask().onPostExecute(): "
						+ e.getMessage());
			}

			mUrlUnshortCallBack.onExtractUrl(result, unshortedUrl);

			super.onPostExecute(null);
		}

	}

	private void getServicesUntiny() {
		Log.i("crawDroid", ".getServicesUntiny(), Start");

		try {
			URL url = new URL(UNTINY_API_SERVICES);
			// mUrlCallBack.setMethod(METHOD_GET_SERVICE_UNTINY);
			// new HttpGetAsyncTask(mUrlCallBack).execute(url.toExternalForm());
			new GetServicesUntinyAsyncTask().execute(url.toExternalForm());

		} catch (IllegalArgumentException e) {
			Log.e("crawDroid", ".unshortUrl(): " + e.getMessage());

		} catch (IOException e) {
			Log.e("crawDroid", ".unshortUrl(): " + e.getMessage());
		}
		Log.i("crawDroid", ".getServicesUntiny(), End");
	}

	private class GetServicesUntinyAsyncTask extends
			AsyncTask<String, Void, String> {

		@Override
		protected String doInBackground(String... params) {
			int responseCode = HttpStatus.SC_NOT_FOUND;
			HttpResponse httpResponse = null;
			HttpEntity entity = null;
			String content = null;

			try {

				HttpGet mHttpGet = new HttpGet(params[0]);
				DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
				httpResponse = defaultHttpClient.execute(mHttpGet);
				// this.execute(params[0]);

				responseCode = httpResponse.getStatusLine().getStatusCode();

				if (responseCode == HttpStatus.SC_OK) {
					entity = httpResponse.getEntity();
					content = EntityUtils.toString(entity);
				} else {
					Log.e("crawDroid", ".HttpGetAsyncTask() response code: "
							+ responseCode);
				}
			} catch (ClientProtocolException e) {
				Log.e("crawDroid", ".unshortUrlAsyncTask(): " + e.getMessage());
			} catch (IOException e) {
				Log.e("crawDroid", ".unshortUrlAsyncTask(): " + e.getMessage());
			} catch (ParseException e) {
				Log.e("crawDroid", ".unshortUrlAsyncTask(): " + e.getMessage());
			}

			return content;
		}

		@Override
		protected void onPostExecute(String httpContent) {
			int result = 0;
			try {
				mUntinyServices = new JSONObject(httpContent);

				if (!mUntinyServices.isNull("error")) {
					JSONArray jsonArray = mUntinyServices.getJSONArray("error");
					result = jsonArray.getInt(0);
					Log.e("crawDroid", ".unshortUrl(), UNTINY API ERROR "
							+ result + " " + jsonArray.getString(1));
				} else {
					Log.v("crawDroid", ".getServicesUntiny(),"
							+ " list of available services downloaded from "
							+ UNTINY_API_SERVICES);
				}

			} catch (JSONException e) {
				Log.e("crawDroid",
						".unshortUrl().onFinish(): " + e.getMessage());
			} catch (ParseException e) {
				Log.e("crawDroid",
						".unshortUrl().onFinish(): " + e.getMessage());
			}

			mUrlUnshortCallBack.onReceiveServices(result);
			// mHandler.sendEmptyMessage(GET_SERVICES);
			super.onPostExecute(null);
		}

	}

	private boolean shortServiceAreAvailable(String shortServiceURL) {
		boolean shortServiceURLAvailable = false;
		Iterator<String> untinyServiceIterator;

		if (mUntinyServices == null || TextUtils.isEmpty(shortServiceURL)) {
			return shortServiceURLAvailable;
		}

		untinyServiceIterator = mUntinyServices.keys();

		while (untinyServiceIterator.hasNext() && !shortServiceURLAvailable) {
			if (TextUtils.equals(shortServiceURL, untinyServiceIterator.next())) {
				Log.v("crawDroid",
						".checkService(), Service available on untiny for: "
								+ shortServiceURL);
				shortServiceURLAvailable = true;
			}
		}

		if (!shortServiceURLAvailable) {
			Log.i("crawDroid",
					".checkService(), no service available on untiny for: "
							+ shortServiceURL);
		}

		return shortServiceURLAvailable;
	}

}
